package com.smt.modules.app.controller;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.smt.common.utils.Constant;
import com.smt.common.utils.StringToListUtil;
import com.smt.modules.app.utils.WebSocketMapUtil;
import com.smt.modules.bus.entity.MemberUserEntity;
import com.smt.modules.bus.entity.ProjectTaskEntity;
import com.smt.modules.bus.entity.SubtaskEntity;
import com.smt.modules.bus.entity.TeamEntity;
import com.smt.modules.bus.service.*;
import com.smt.modules.bus.service.impl.MemberUserServiceImpl;
import com.smt.modules.bus.service.impl.TeamServiceImpl;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.MySQLGroupConcat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.socket.server.standard.SpringConfigurator;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Base64;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * 推送消息
 * userInfo : 当前发送者id
 *
 * @author zhangyi
 * @date 2018/11/9 11:50
 */
@ServerEndpoint(value = "/app/message/{userInfo}")
@Slf4j
@Api(tags = {"AppPushMessageController"}, description = "消息推送接口(客户端接口)")
@RestController
public class AppPushMessageController {
    /**
     * 查看当前的在线个数
     */
    private static int currentCount = 0;

    /**
     * 复制一个副本对去进行set对象
     */
    private static CopyOnWriteArraySet<AppPushMessageController> webSocketSet = new CopyOnWriteArraySet<>();

    /**
     * 单独保存的用户信息
     */
    private static ConcurrentHashMap<String, AppPushMessageController> userSocket = new ConcurrentHashMap<>();

    /**
     * 与客户端连接时候，发送给客户端数据
     */
    private Session session;

    /**
     * 当前发送者用户id
     */
    private String userInfo;
    /**
     *  创建团队服务
     */
    public static TeamService teamService ;
    /**
     * 创建用户服务
     */
    public static MemberUserService memberUserService ;

    /**
     * 创建子任务服务
     */
    public static SubtaskService subtaskService;

    /**
     * 任务服务
     */
    public static ProjectTaskService projectTaskService;

    /**
     * 存储消息
     */
    public static MessageHandleService messageHandleService;

    /**
     * 调用成功时候的方法
     */
    @OnOpen
    public void onOpen(@PathParam(value = "userInfo") String paramUserInfo, Session session) {
        log.info("获取到的用户id：{}", paramUserInfo);
        userInfo = paramUserInfo;
        this.session = session;
        //添加用户信息
        userSocket.put(paramUserInfo, this);
        //添加当前发送信息
        webSocketSet.add(this);
        addCurrent();
        log.info("有新的用户连接加入---当前人数：{}", getCurrentCount());
    }

    @OnClose
    public void onClose() {
        webSocketSet.remove(this);
        userSocket.remove(userInfo);
        subCurrent();
        log.info("有一个用户已经下线---当前人数：{}", getCurrentCount());
    }

    /**
     * 接收到客户端的消息
     *
     * @param message
     * @throws IOException
     */
    @OnMessage
    public void onMessage(String message) throws IOException {
        log.info("接受客户端的消息：" + message);

        //约定信息格式  作为分割 [发送的数据]-[用户id],[],[]...
        String[] split = message.split(Constant.FILE_SPILT);
        String messageInfo = split[0];
        String messageId = split[1];
        if (messageId.equals("0")) {
            //群发消息
            sendAllMessage(messageInfo);
        } else {
            //当前用户id
            String localUser = this.userInfo;
            //被发送者id集合
            String[] recipient = messageId.split(",");
            //第一个id是区分是否独立分发，是否项目全员分发
            String s = recipient[0];
            String[] firstMessage = s.split("@");
            //状态位 0全项目转发 1分类成员转发 2 3
            Integer status = Integer.parseInt(firstMessage[0]);
            //消息格式：
            // 项目全员发送消息-0@81
            // 独立发送消息-1@0,67
            // 指定用户消息发送-1@0,68,67

            //发送给阶段成员下的所有任务和子任务负责人-2@81#6（81：项目id 6：阶段id）
            switch (status) {
                case 0:
                    //项目id
                    Long projectId = Long.parseLong(firstMessage[1]);
                    //整个项目
                    sendAllProjectMessage(messageInfo, projectId);
                    break;
                case 1:
                    //批量发送信息
                    for (int i = 1; i < recipient.length; i++) {
                        //发送指定消息
                        sendToUser(messageInfo, Long.parseLong(recipient[i]));
                    }
                    break;
                case 2:
                    //发送给阶段成员下的所有任务和子任务负责人-2@81#6
                    //项目id和阶段id
                    String proAndStage = firstMessage[1];
                    String[] messageStage = proAndStage.split("#");
                    //项目id
                    String proId = messageStage[0];
                    //阶段id
                    String stageId = messageStage[1];
                    //查询旗下的用户id将其一次分发
                    sendAllStageMessage(messageInfo,Long.parseLong(proId),Integer.parseInt(stageId));
                    break;
                case 3:
                    //发送给任务下的所有子任务负责人-3@1345
                    //任务id
                    Long taskId = Long.parseLong(firstMessage[1]);
                    sendAllSubTaskMessage(taskId,new StringBuffer(messageInfo));
                    break;
                default:
                    log.error("消息格式错误 {}", recipient);
                    break;
            }
        }
    }

    /**
     * 多播项目自定义消息(消息接收对象：项目下的阶段全体成员)
     *
     * @param message
     **/
    public void sendAllStageMessage(String message, Long projectId,Integer stage){
        StringBuffer messageBuffer = new StringBuffer(message);
        List<ProjectTaskEntity> projectTaskList = projectTaskService.selectList(new EntityWrapper<ProjectTaskEntity>()
                .eq("project_id", projectId)
                .eq("stage_id", stage)
                .eq("status",Constant.SQL_CON)
                .eq("member_exist",0));
        try {
            //发送负责人消息
            for (ProjectTaskEntity p : projectTaskList) {
                Long memberId = p.getMemberId();
                Long id = p.getId();
                if (!Objects.isNull(memberId)) {
                    sendToUser(messageBuffer.toString(), memberId);
                }
                //发送子任务消息
                sendAllSubTaskMessage(id,messageBuffer);
            }
        }catch (IOException e){
            log.error("消息发送负责人错误:{}",e.getMessage());
        }
        //发送阶段负责人消息
    }

    public void sendAllSubTaskMessage(Long taskId, StringBuffer messageBuffer) throws IOException {
        //消息分发给子任务责任人
        List<SubtaskEntity> subtaskEntities = subtaskService.selectList(new EntityWrapper<SubtaskEntity>()
                .eq("project_task_id", taskId)
                .eq("status", Constant.SQL_CON)
                .eq("member_exist", 0)
                .orderBy("create_time", false));
        if(!Objects.isNull(subtaskEntities) && subtaskEntities.size() != 0){
            for(SubtaskEntity s : subtaskEntities){
                Long subMemberId = s.getMemberId();
                if(!Objects.isNull(subMemberId)){
                    sendToUser(messageBuffer.toString(), subMemberId);
                }
            }
        }
    }
    /**
     * 群发项目自定义消息(消息接收对象：项目全体成员)
     *
     * @param message
     **/
    public void sendAllProjectMessage(String message, Long projectId) throws IOException {
        List<TeamEntity> teamEntities = teamService.selectList(new EntityWrapper<TeamEntity>()
                .eq("project_id", projectId)
                .eq("member_exist", 0));
        for (TeamEntity t : teamEntities) {
            Long memberId = t.getMemberId();
            MemberUserEntity memberUserEntity = memberUserService.selectById(memberId);
            Long userId = memberUserEntity.getUserId();
            sendToUser(message, userId);
        }
    }

    /**
     * 群发自定义消息
     *
     * @param message
     **/
    public static void sendAllMessage(String message) throws IOException {
        for (AppPushMessageController item : webSocketSet) {
            try {
                item.sendMessage(message);
                log.info("群发消息");
            } catch (IOException e) {
                continue;
            }
        }
    }

    /**
     * 群发给指定用户的消息
     *
     * @param message
     **/
    public void sendToUser(String message, Long sendUserId) throws IOException {
        //加入自己的业务逻辑
        MemberUserEntity memberUserEntity = memberUserService.selectById(sendUserId);
        if(!Objects.isNull(memberUserEntity)){
            String messageId = memberUserEntity.getMessageId();
            if (userSocket.get(messageId) != null) {
                if (!userInfo.equals(messageId)) {
                    userSocket.get(messageId).sendMessage(message);
                } else {
                    userSocket.get(messageId).sendMessage(message);
                }
            } else {
                //如果用户不在线则返回不在线信息给自己
//                sendToUser("当前用户不在线", userInfo);
            }
        }else{
            log.error("用户实体不存在。发送消息错误 发送消息：{} 发送者id：{}",message,sendUserId);
        }
    }

    @OnError
    public void onError(Session session, Throwable error) {
        System.out.println("消息发送错误，系统异常");
        error.printStackTrace();
    }


    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    public Integer getCurrentCount() {
        return currentCount;
    }

    public static synchronized void addCurrent() {
        currentCount++;
    }

    public static synchronized void subCurrent() {
        currentCount--;
    }

    /**
     * 数据编码
     *
     * @param message
     * @return
     */
    private String encoderMessage(String message){
        Base64.Encoder encoder = Base64.getEncoder();
        byte[] encode = new byte[0];
        try {
            encode = encoder.encode(new String(message.getBytes("UTF8"),"UTF8").getBytes());
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        String s = new String(encode, 0, encode.length);
        log.info("接受的消息是：{} 编码后：{}",message,s);
        return s;
    }

    /**
     * 数据解码
     *
     * @param message
     * @return
     */
    private String decoderMessage(String message){
        Base64.Decoder decoder = Base64.getDecoder();
        byte[] encode1 = decoder.decode(message.getBytes());
        String s1 = new String(encode1, 0, encode1.length);
        log.info("转化后的消息：{}",s1);
        return s1;
    }
}
